package cn.jiedh.app.meiweidk.Utils.tool;

import cn.jiedh.app.meiweidk.app.EnvConfig;

import java.math.BigInteger;
import java.security.Key;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.Signature;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.HashMap;
import java.util.Map;

import javax.crypto.Cipher;


/**
 * @ClassName: RSAUtils
 * @Description: TODO RSA加密解密工具
 * @author: hayder
 * @date: 2017年10月9日 下午4:33:15
 */
public class RSAUtils {
    /**
     * 编码
     */
    private static final String UTF8 = "UTF-8";
    /**
     * 加密算法RSA
     */
    public static final String KEY_ALGORITHM = "RSA";
    /**
     * 签名算法
     */
    public static final String SIGNATURE_ALGORITHM = "MD5withRSA";
    /**
     * APP KEY
     */
    public static String APP_KEY = EnvConfig.APP_KEY;
    /**
     * 获取公钥的key
     */
//    public static String PUBLIC_KEY =AuditConstant.releasePublic_Key;
    public static String PUBLIC_KEY = EnvConfig.PUBLIC_KEY;
    /**
     * 获取私钥的key
     */
//    public static String PRIVATE_KEY = AuditConstant.releasePrivate_Key;
    public static String PRIVATE_KEY = EnvConfig.PRIVATE_KEY;

    /**
     * <p>
     * 生成密钥对(公钥和私钥)
     * </p>
     *
     * @return
     * @throws Exception
     */
    public static Map<String, Object> genKeyPair() throws Exception {
        KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(KEY_ALGORITHM);
        keyPairGen.initialize(KEY_MAX_LENGTH);
        KeyPair keyPair = keyPairGen.generateKeyPair();
        RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
        RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
        Map<String, Object> keyMap = new HashMap<String, Object>(2);
        keyMap.put(PUBLIC_KEY, publicKey);
        keyMap.put(PRIVATE_KEY, privateKey);
        return keyMap;
    }

    /**
     * <p>
     * 获取私钥
     * </p>
     *
     * @param keyMap 密钥对
     * @return
     * @throws Exception
     */
    public static String getPrivateKey(Map<String, Object> keyMap) throws Exception {
        Key key = (Key) keyMap.get(PRIVATE_KEY);
        return Base64Utils.encode(key.getEncoded());
    }

    /**
     * <p>
     * 获取公钥
     * </p>
     *
     * @param keyMap 密钥对
     * @return
     * @throws Exception
     */
    public static String getPublicKey(Map<String, Object> keyMap) throws Exception {
        Key key = (Key) keyMap.get(PUBLIC_KEY);
        return Base64Utils.encode(key.getEncoded());
    }

    /**
     * 密钥长度
     */
    private static final int KEY_MAX_LENGTH = 1024;

    /**
     * 私钥加密
     *
     * @param key  私钥
     * @param data 明文
     * @return <b>String</b> 密文<b><br/>null</b> 加密失败
     */
    public static String encryptByPrivateKey(String key, byte[] data) {
        try {
            RSAPrivateKey privateKey = getPrivateKey(key);
            Cipher cipher = Cipher.getInstance(KEY_ALGORITHM);
            cipher.init(Cipher.ENCRYPT_MODE, privateKey);
            byte[] rsa = cipher.doFinal(data);
            return Base64Utils.byteArrayToBase64(rsa);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 私钥加密
     *
     * @param key  私钥
     * @param data 明文
     * @return <b>String</b> 密文<b><br/>null</b> 加密失败
     */
    public static String encryptByPrivateKey(String key, String data) {
        try {
            byte[] bdata = StringUtil.strToByte(data);
            RSAPrivateKey privateKey = getPrivateKey(key);
            Cipher cipher = Cipher.getInstance(KEY_ALGORITHM);
            cipher.init(Cipher.ENCRYPT_MODE, privateKey);
            byte[] rsa = cipher.doFinal(bdata);
            return Base64Utils.byteArrayToBase64(rsa);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 公钥加密
     *
     * @param key  公钥
     * @param data 明文
     * @return <b>String</b> 密文<b><br/>null</b> 加密失败
     */
    public static String encryptByPublicKey(String key, byte[] data) {
        try {
            RSAPublicKey publicKey = getPublicKey(key);
            Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
            cipher.init(Cipher.ENCRYPT_MODE, publicKey);
            byte[] rsa = cipher.doFinal(data);
            return Base64Utils.byteArrayToBase64(rsa);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 公钥加密
     *
     * @param key  公钥
     * @param data 明文
     * @return <b>String</b> 密文<b><br/>null</b> 加密失败
     */
    public static String encryptByPublicKey(String key, String data) {
        try {
            byte[] bdata = StringUtil.strToByte(data);
            RSAPublicKey publicKey = getPublicKey(key);
            Cipher cipher = Cipher.getInstance(KEY_ALGORITHM);
            cipher.init(Cipher.ENCRYPT_MODE, publicKey);
            byte[] rsa = cipher.doFinal(bdata);
            return Base64Utils.byteArrayToBase64(rsa);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 私钥解密
     *
     * @param key  私钥
     * @param data 密文
     * @return <b>String</b> 明文<b><br/>null</b> 解密失败
     */
    public static String decryptByPrivateKey(String key, byte[] data) {
        try {
            RSAPrivateKey privateKey = getPrivateKey(key);
            Cipher cipher = Cipher.getInstance(KEY_ALGORITHM);
            cipher.init(Cipher.DECRYPT_MODE, privateKey);
            byte[] rsa = cipher.doFinal(data);
            return new String(rsa, UTF8);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 私钥解密
     *
     * @param key  私钥
     * @param data 密文
     * @return <b>String</b> 明文<b><br/>null</b> 解密失败
     */
    public static String decryptByPrivateKey(String key, String data) {
        try {
            byte[] bdata = Base64Utils.base64ToByteArray(data);
            RSAPrivateKey privateKey = getPrivateKey(key);
            Cipher cipher = Cipher.getInstance(KEY_ALGORITHM);
            cipher.init(Cipher.DECRYPT_MODE, privateKey);
            byte[] rsa = cipher.doFinal(bdata);
            return new String(rsa, UTF8);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 公钥解密
     *
     * @param key  公钥
     * @param data 密文
     * @return <b>String</b> 明文<b><br/>null</b> 解密失败
     */
    public static String decryptByPublicKey(String key, byte[] data) {
        try {
            RSAPublicKey publicKey = getPublicKey(key);
            Cipher cipher = Cipher.getInstance(KEY_ALGORITHM);
            cipher.init(Cipher.DECRYPT_MODE, publicKey);
            byte[] rsa = cipher.doFinal(data);
            return new String(rsa, UTF8);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 公钥解密
     *
     * @param key  公钥
     * @param data 密文
     * @return <b>String</b> 明文<b><br/>null</b> 解密失败
     */
    public static String decryptByPublicKey(String key, String data) {
        try {
            byte[] bdata = Base64Utils.base64ToByteArray(data);
            RSAPublicKey publicKey = getPublicKey(key);
            Cipher cipher = Cipher.getInstance(KEY_ALGORITHM);
            cipher.init(Cipher.DECRYPT_MODE, publicKey);
            byte[] rsa = cipher.doFinal(bdata);
            return new String(rsa, UTF8);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * <p>
     * 用私钥对信息生成数字签名
     * </p>
     *
     * @param data       已加密数据
     * @param privateKey 私钥(BASE64编码)
     * @return
     * @throws Exception
     */
    public static String sign(byte[] data, String privateKey) throws Exception {
        byte[] keyBytes = Base64Utils.decode(privateKey);
        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        PrivateKey privateK = keyFactory.generatePrivate(pkcs8KeySpec);
        Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
        signature.initSign(privateK);
        signature.update(data);
        return Base64Utils.encode(signature.sign());

//		 //用私钥进行签名  
//        PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(rsaPrivateKey.getEncoded());  //私钥转换成pkcs8格式  
//        KeyFactory keyFactory = KeyFactory.getInstance("RSA");  
//        PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec); // 用key工厂对象生成私钥  
//        Signature signature = Signature.getInstance("MD5withRSA");  //  md5 RSA签名对象  
//        signature.initSign(privateKey);  //初始化签名  
//        signature.update(src.getBytes());  
//        byte[] result = signature.sign();  //对消息进行签名  
//        System.out.println("签名结果："+result);  
//          
//          
//        //用公钥进行验证  
//        X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(rsaPublicKey.getEncoded());  
//        PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec);  
//        signature.initVerify(publicKey);  
//        signature.update(src.getBytes());  
//        boolean verify = signature.verify(result);  
//        System.out.println("验证结果:"+verify);  
    }

    /**
     * <p>
     * 校验数字签名
     * </p>
     *
     * @param data      已加密数据
     * @param publicKey 公钥(BASE64编码)
     * @param sign      数字签名
     * @return
     * @throws Exception
     */
    public static boolean verify(byte[] data, String publicKey, String sign) throws Exception {
        byte[] keyBytes = Base64Utils.decode(publicKey);
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        PublicKey publicK = keyFactory.generatePublic(keySpec);
        Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
        signature.initVerify(publicK);
        signature.update(data);
        byte[] d = Base64Utils.decode(sign);
        return signature.verify(d);
    }

    /**
     * JS密钥对
     *
     * @param size 密钥长度
     * @return 密钥对
     */
    public static Map<String, String> genJsKey(int size) {
        Map<String, String> keyMap = new HashMap<String, String>();
        try {
            KeyPairGenerator keygen = KeyPairGenerator.getInstance("RSA");
            keygen.initialize(size, new SecureRandom());
            KeyPair keyPair = keygen.generateKeyPair();
            RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
            RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
            BigInteger n = privateKey.getModulus();
            BigInteger e = publicKey.getPublicExponent();
            BigInteger d = privateKey.getPrivateExponent();
            String p = Base64Utils.byteArrayToBase64(privateKey.getEncoded());
            keyMap.put("n", n.toString(16));
            keyMap.put("e", e.toString(16));
            keyMap.put("d", d.toString(16));
            keyMap.put("p", p);
        } catch (Exception e) {
        }
        return keyMap;
    }

    /**
     * JS密文解密
     *
     * @param key  私钥
     * @param data 密文
     * @return <b>String</b> 明文<b><br/>null</b> 解密失败
     */
    public static String decryptJsData(String key, String data) {
        try {
            byte[] bdata = hexToByte(StringUtil.strToByte(data));
            RSAPrivateKey privateKey = getPrivateKey(key);
            Cipher cipher = Cipher.getInstance(KEY_ALGORITHM);
            cipher.init(Cipher.DECRYPT_MODE, privateKey);
            byte[] rsa = cipher.doFinal(bdata);
            return new String(rsa, UTF8);
        } catch (Exception e) {
        }
        return null;
    }

    private static RSAPrivateKey getPrivateKey(String key) {
        try {
            byte[] keyBytes = Base64Utils.base64ToByteArray(key);
            PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(keyBytes);
            KeyFactory factory = KeyFactory.getInstance("RSA");
            return (RSAPrivateKey) factory.generatePrivate(spec);
        } catch (Exception e) {
        }
        return null;
    }

    private static RSAPublicKey getPublicKey(String key) {
        try {
//            byte[] keyBytes = Base64Utils.base64ToByteArray(key);
////            byte[] keyBytes=key.getBytes();
//            X509EncodedKeySpec spec = new X509EncodedKeySpec(keyBytes);
//            KeyFactory factory = KeyFactory.getInstance("RSA");

            byte[] keyBytes = Base64Utils.decode(key);
            X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            PublicKey publicKey = keyFactory.generatePublic(keySpec);
            return (RSAPublicKey) publicKey;
//            return (RSAPublicKey) factory.generatePublic(spec);
        } catch (Exception e) {
        }
        return null;
    }


    private static byte[] hexToByte(byte[] hex) {
        if (hex.length % 2 != 0) {
            return null;
        }
        byte[] b = new byte[hex.length / 2];
        for (int i = 0; i < hex.length; i += 2) {
            String str = new String(hex, i, 2);
            b[i / 2] = (byte) Integer.parseInt(str, 16);
        }
        return b;
    }

    public static void main(String[] args) {
        String data = "我是JAVA开发者";
        String data1 = "我是JAVA开发者1";
        try {
//			Map<String, Object> keyMap;
//			keyMap = genKeyPair();
//		String publicKey=getPublicKey(keyMap);
//		String privateKey=getPrivateKey(keyMap);
            String publicKey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQChl6ZG2W0pS8iHWGK3U3EM0kQCXGA5+1bl9jvPoaKGJptX9z1S5QkjLkOp7+2kXVeK65cJ2eviZE0Nj2yeQH/Xj9WpDMwDslAV27vzQ88MbyLcKeOLBm+h7oSwCNYT3XHrtv5TP38nUkZxWRSS4xnu5mg2OM0p5VGgfrb/7TORUQIDAQAB";
            String privateKey = "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAKGXpkbZbSlLyIdYYrdTcQzSRAJcYDn7VuX2O8+hooYmm1f3PVLlCSMuQ6nv7aRdV4rrlwnZ6+JkTQ2PbJ5Af9eP1akMzAOyUBXbu/NDzwxvItwp44sGb6HuhLAI1hPdceu2/lM/fydSRnFZFJLjGe7maDY4zSnlUaB+tv/tM5FRAgMBAAECgYBiyhWLhu1nq78Cj5R6Q3b/waR2VQc3K2Nq32idfVGg9gVOeAZzoTY+3c/cGqSMMcyNT45dJW9CTtOUkLR04zXEFJiZ06IneayaXICAtwgUwNC3QBz5ngQ0ptW6R/wAXWfosmmNzAhJvYwyThDqoYQyy0LC49+gbm5wlRdm2jqXaQJBAPOhRuZ0gwQ293gC3D1xIlYoWYLOA/GyWR646Ss78NQL/IYJOh6ovw3ivv3Oy5SJGZBmc6qXBSWNxyQD4ywxEisCQQCpzAp1mMUwXaoh+E/urrRBGE90fa1zI2wJWY0/UhZMx5cUHSIWxGc7rLQeS+u2FRscv1WPYkRm7uhSR0jBDThzAkAderRTimGYDvaexOnVXW0kM7mxBDCh/EygVQuRua0IW3Lw3Qj1UMHdckRd/bnQfU5klKEGUUPEKYWhK/8/B6kFAkBHPvlojJi5CaQ4qsOHaED0S2oTfCSKemN7rNrKpfv7bYgkBXFnUjPq4zWUvNCDz2lX76TMDDSdaEONOqH5dz2nAkEA1pgWEv/weB2xi+aDon77qyQJD0al24WY4VaJ8MDS7xZ5aW3yVcLYj+ZFdc4gmu4stx5VmM/RdVUIayGFXb1cUQ==";
            System.out.println("publicKey:" + publicKey);
            System.out.println("privateKey:" + privateKey);
            //用公钥加密私钥解密
            String dataJson = RSAUtils.encryptByPublicKey(publicKey, data);
            System.out.println(dataJson);

            System.out.println(RSAUtils.decryptByPrivateKey(privateKey, dataJson));
            //用私钥加密公钥解密
            String dataJson1 = RSAUtils.encryptByPrivateKey(privateKey, data1);
            System.out.println(dataJson1);
            System.out.println(RSAUtils.decryptByPublicKey(publicKey, dataJson1));
            //公钥解密
            System.out.println(RSAUtils.decryptByPublicKey(publicKey, dataJson1));
            //私钥解密
            System.out.println(RSAUtils.decryptByPrivateKey(privateKey, "ar2t4xhDFf4/PPpu1fHfJ8OiqvuaScs2r1qelCF71e6s9+9eAEgCptvBchMnh0xJdW0oB9Bgd3l6eBY0OyN0I2BlHebJreeTxK0qXH99B5jgpcfE57CiKeIkktOvwgSdi9ZHJlU9p3HhQll+FpVUCkaRdXzqdl65WCILFJrwojw="));

            String sign = RSAUtils.sign("ios工程师".getBytes(), privateKey);
            System.out.println(sign);
            System.out.println(RSAUtils.verify("iOS RSA加解密签名和验证".getBytes(), publicKey, "YnDmU5K2rsswETxwxTJGF3embZjOX+ClK9BhxSfE/Red5H9DHxaP15pqIbSKG+dG1iYxJfod1kYVog6vky9V2cTuGdH8jlsDRXvdG33qp26vKEt3nXdDZsv5mO2gRUdlevZETkySwpPZ7wOP6AiSYGRXRp3PiAjJMD6dgQz+ckg="));

        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}